package com.admin.common.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;

/**
 * HttpClient工具类，请勿随意扩展
 */
public class HttpClientUtil {

    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);

    // 超时时间20秒
    static final Integer DEFALUT_TIMEOUT = 40;

    // 以域名和端口为key，CloseableHttpClient为value
    private static Map<String, CloseableHttpClient> httpClientMap = new HashMap<String, CloseableHttpClient>();

    /**
     * 对Request进行配置
     * 
     * @param httpRequestBase
     * @param timeout 超时时长，单位秒
     */
    private static void configRequest(HttpRequestBase httpRequestBase, Integer timeout) {
        // 设置超时时间
        if (timeout == null) {
            timeout = DEFALUT_TIMEOUT;
        }
        timeout = timeout * 1000;
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeout)
            .setConnectTimeout(timeout).setSocketTimeout(timeout).build();
        httpRequestBase.setConfig(requestConfig);
    }

    /**
     * 获取HttpClient对象
     *
     * @return
     */
    private static CloseableHttpClient getHttpClient(String hostport) {
        CloseableHttpClient httpClient = httpClientMap.get(hostport);
        if (httpClient == null) {
            synchronized (httpClientMap) {
                if (httpClient == null) {
                    httpClient = createHttpClient(10000, 1000, 10000, hostport.split(":")[0],
                        Integer.valueOf(hostport.split(":")[1]));
                }
            }
        }
        return httpClient;
    }

    /**
     * 创建一个HttpClient（该HttpClient发起的连接，底层用连接池管理）
     * 
     * @param maxTotal 该HttpClient最大的连接数
     * @param defaultMaxPerRoute 默认每个route最大连接数
     * @param maxPerRoute 每个route最大连接数
     * @param hostname
     * @param port
     * @return
     */
    private static CloseableHttpClient createHttpClient(int maxTotal, int defaultMaxPerRoute, int maxPerRoute,
        String hostname, int port) {

        // http，https两种ConnectionSocketFactory
        ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();

        // ConnectionSocketFactory的Registry
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", plainsf).register("https", sslsf).build();

        // HttpClientConnectionManager连接池管理器
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);

        // 每个HttpClient维护的最大连接数
        cm.setMaxTotal(maxTotal);

        // 默认每个主机地址最大连接数
        cm.setDefaultMaxPerRoute(defaultMaxPerRoute);

        // 每个主机地址最大连接数
        HttpHost httpHost = new HttpHost(hostname, port);
        cm.setMaxPerRoute(new HttpRoute(httpHost), maxPerRoute);

        // 每个主机地址对应的CloseableHttpClient
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();
        httpClientMap.put(hostname + ":" + port, httpClient);
        return httpClient;
    }

    /**
     * 设置post请求参数
     *
     * @param httpost
     * @param params
     */
    private static void setPostParams(HttpPost httpost, Map<String, Object> params) {
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        Set<String> keySet = params.keySet();
        for (String key : keySet) {
            try {
                nvps.add(new BasicNameValuePair(key, params.get(key).toString()));
            } catch (Exception ex) {
                continue;
            }
        }
        try {
            httpost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            logger.error("异常{}", e);
        }
    }

    /**
     * 设置post请求参数
     *
     * @param httpost
     * @param params
     */
    private static void setPostParams(HttpPost httpost, String params) {
        StringEntity entity = new StringEntity(params, "utf-8");
        entity.setContentType(ContentType.APPLICATION_JSON.getMimeType());
        httpost.setEntity(entity);
    }

    /**
     * 获取域名端口
     *
     * @param url
     * @return
     */
    private static String getHostPort(String url) {
        String hostPort = url.split("/")[2];
        if (!hostPort.contains(":")) {
            hostPort = hostPort + ":80";// url中未写端口号则认为使用默认80端口
        }
        return hostPort;
    }

    /**
     * post提交
     * 
     * @param url
     * @param params 参数名为key，参数值为value
     * @return
     */
    public static String post(String url, Map<String, Object> params) {
        return post(url, params, DEFALUT_TIMEOUT);
    }

    /**
     * post提交
     * 
     * @param url
     * @param params 参数名为key，参数值为value
     * @param timeout 超时时间，单位秒
     * @return
     */
    public static String post(String url, Map<String, Object> params, Integer timeout) {
        HttpPost httpPost = new HttpPost(url);
        configRequest(httpPost, timeout);
        setPostParams(httpPost, params);
        CloseableHttpResponse response = null;
        try {
            response = getHttpClient(getHostPort(url)).execute(httpPost, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "utf-8");
            // 执行该方法，会清空流，要不会在内存中持有浪费资源。
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            logger.error("异常{}", e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                logger.error("异常{}", e);
            }
        }
        return "";
    }

    /**
     * post提交
     * 
     * @param url
     * @param myclass 参数为对象
     * @return
     */
    public static String post(String url, Object myclass) {
        return post(url, myclass, DEFALUT_TIMEOUT);
    }

    /**
     * post提交
     * 
     * @param url
     * @param myclass
     * @param timeout，单位秒
     * @return
     */
    public static String post(String url, Object myclass, Integer timeout) {
        HttpPost httpPost = new HttpPost(url);
        configRequest(httpPost, timeout);
        String jsonSting = JSON.toJSONString(myclass);
        StringEntity stringEntity = new StringEntity(jsonSting, "UTF-8");
        httpPost.setEntity(stringEntity);
        httpPost.setHeader("Content-Type", "application/json;charset=utf8");
        CloseableHttpResponse response = null;
        try {
            response = getHttpClient(getHostPort(url)).execute(httpPost, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "utf-8");
            // 执行该方法，会清空流，要不会在内存中持有浪费资源。
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            logger.error("异常{}", e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                logger.error("异常{}", e);
            }
        }
        return "";
    }

    /**
     * post提交
     * 
     * @param url
     * @param params 参数为json
     * @return
     */
    public static String post(String url, String params) {
        return post(url, params, DEFALUT_TIMEOUT);
    }

    /**
     * post提交
     * 
     * @param url
     * @param params 参数为json
     * @param timeout 超时时间，单位秒
     * @return
     */
    public static String post(String url, String params, Integer timeout) {
        HttpPost httpPost = new HttpPost(url);
        String hostPort = getHostPort(url);
        configRequest(httpPost, timeout);
        setPostParams(httpPost, params);
        CloseableHttpResponse response = null;
        try {
            response = getHttpClient(hostPort).execute(httpPost, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "utf-8");
            // 执行该方法，会清空流，要不会在内存中持有浪费资源。
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            logger.error("异常{}, url{}, params{}", e, url, params);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                logger.error("异常{}", e);
            }
        }
        return "";
    }

    /**
     * get请求
     * 
     * @param url
     * @return
     */
    public static String get(String url) {
        return get(url, DEFALUT_TIMEOUT);
    }

    /**
     * get请求
     * 
     * @param url
     * @param timeout，单位秒
     * @return
     */
    public static String get(String url, Integer timeout) {
        HttpGet httpGet = new HttpGet(url);
        String hostPort = getHostPort(url);
        configRequest(httpGet, timeout);
        CloseableHttpResponse response = null;
        try {
            response = getHttpClient(hostPort).execute(httpGet, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "utf-8");
            // 执行该方法，会清空流，要不会在内存中持有浪费资源。
            EntityUtils.consume(entity);
            return result;
        } catch (IOException e) {
            logger.error("异常{}", e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                logger.error("异常{}", e);
            }
        }
        return "";
    }

    public static void main(String[] args) {
        // String[] str = "http://139.224.112.220:9945".split("/");
        // System.out.println(str);
        // System.out.println("http://139.224.112.220:9945".split("/").toString());
        System.out.println(post("http://139.224.112.220:9945/query_bank_card_bin", new HashMap<>()));
    }
}